package cn.lg.soar.mvc.util;

import cn.lg.soar.common.data.msg.I18n;
import cn.lg.soar.common.exceptions.AuthenticationException;
import cn.lg.soar.common.exceptions.ParameterException;
import cn.lg.soar.common.exceptions.PermissionException;
import cn.lg.soar.common.model.HttpResult;
import cn.lg.soar.common.util.data.DataUtil;
import cn.lg.soar.common.util.jackson.JacksonUtil;
import com.alibaba.excel.support.ExcelTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.util.StreamUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/**
 * 响应工具
 * @author luguoxiang
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public class ResponseUtils {

    protected static final Logger LOGGER = LoggerFactory.getLogger(ResponseUtils.class);

    private final static String CONTENT_TYPE_HTML = "text/html;charset=UTF-8";
    private final static String LOGIN_JSON = JacksonUtil.toJson(HttpResult.fail(new AuthenticationException()));
    private final static String PERMISSION_JSON = JacksonUtil.toJson(HttpResult.fail(new PermissionException()));
    private final static String ERROR_JSON = JacksonUtil.toJson(HttpResult.fail());

    public static void responseBody(HttpServletResponse response, String text) {
        response.setContentType(ResponseUtils.CONTENT_TYPE_HTML);
        try (PrintWriter out = response.getWriter()){
            out.write(text);
            out.flush();
        } catch (IOException e) {
            LOGGER.error("写响应内容失败", e);
        }
    }

    public static void responseBody(HttpServletResponse response, Object data) {
        ResponseUtils.responseBody(response, JacksonUtil.toJson(data));
    }

    public static void responseBody(String text) {
        responseBody(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getResponse(), text);
    }

    public static void responseBody(Object data) {
        responseBody(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getResponse(), JacksonUtil.toJson(data));
    }

    public static void E400(HttpServletResponse response, I18n msg, Object... args){
        response.setStatus(400);
        ResponseUtils.responseBody(response, HttpResult.fail(new ParameterException(msg, args)));
    }

    public static void E401(HttpServletResponse response){
        response.setStatus(401);
        ResponseUtils.responseBody(response, ResponseUtils.LOGIN_JSON);
    }

    public static void E403(HttpServletResponse response){
        response.setStatus(403);
        ResponseUtils.responseBody(response, ResponseUtils.PERMISSION_JSON);
    }

    public static void E412(HttpServletResponse response, String msg){
        response.setStatus(412);
        ResponseUtils.responseBody(response, msg);
    }

    public static void E500(HttpServletResponse response){
        response.setStatus(500);
        ResponseUtils.responseBody(response, ResponseUtils.ERROR_JSON);
    }

    public static void setResponseExcel(String fileName, HttpServletResponse response) {
        try {
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/vnd.ms-excel");
            response.setHeader(
                    "Content-disposition",
                    "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ExcelTypeEnum.XLSX.getValue()
            );
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    /**.
     *
     *
     * @param fileName
     * @param response
     */
    public static void setResponseExcel(int status, HttpServletResponse response) {
        response.setStatus(status);
//        response.setCharacterEncoding("utf-8");
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    }

    /**
     * 跨域配置
     * @param response
     * @param origin
     * @param methods
     */
    public static void corsConfig(HttpServletResponse response, String origin, String methods, String headers, String age) {
        response.addHeader("Access-Control-Allow-Origin", origin);
        response.addHeader("Access-Control-Allow-Methods", methods);
        response.addHeader("Access-Control-Allow-Headers", headers);
        response.addHeader("Access-Control-Allow-Max-Age", age);
    }
    public static void corsConfig(HttpServletResponse response, String origin, String methods, String headers){
        corsConfig(response, origin, methods, headers, "3600");
    }
    public static void corsConfig(HttpServletResponse response, String origin, String methods){
        corsConfig(response, origin, methods, "*", "3600");
    }
    public static void corsConfig(HttpServletResponse response, String origin){
        corsConfig(response, origin, "*", "*", "3600");
    }
    public static void corsConfig(HttpServletResponse response){
        corsConfig(response, "*", "*", "*", "3600");
    }

    public static HttpServletResponse getResponse() {
        return ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getResponse();
    }

    /**
     * 响应文件
     * @param inputStream
     * @param filename
     */
    public static void responseFile(InputStream inputStream, String filename) {
        HttpServletResponse resp = getResponse();
        resp.setCharacterEncoding("UTF-8");
        //设置Content-Disposition响应头，一方面可以指定下载的文件名，另一方面可以引导浏览器弹出文件下载窗口
        resp.setHeader("Content-Disposition", "attachment;fileName=\"" + filename + "\"");
        // 文件下载
        try (ServletOutputStream outputStream = resp.getOutputStream()){
            StreamUtils.copy(inputStream, outputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                LOGGER.error("关闭流异常", e);
            }
        }
    }

    public static void responseFile(File file, String filename) {
        if(!file.exists()) {
            return;
        }
        //判断文件类型
        String mimeType = URLConnection.guessContentTypeFromName(file.getName());
        if(mimeType == null) {
            mimeType = "application/octet-stream";
        }
        if(null == filename){
            filename = file.getName();
        }
        String agent = RequestUtils.getHeader("User-Agent");
        // 根据不同的客户端进行不同的编码
        try {
            if (agent.contains("MSIE")) {
                filename = URLEncoder.encode(filename, "utf-8");
            } else if (agent.contains("Firefox")) {
                filename = "=?utf-8?B?" + DataUtil.byteToBase64(filename.getBytes(StandardCharsets.UTF_8)) + "?=";
            } else {
                filename = URLEncoder.encode(filename, "utf-8");
            }
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        HttpServletResponse resp = getResponse();
        //设置Content-Disposition响应头，一方面可以指定下载的文件名，另一方面可以引导浏览器弹出文件下载窗口
        resp.setHeader("Content-Disposition", "attachment;fileName=\"" + filename + "\"");
        resp.setContentType(mimeType);
        resp.setContentLengthLong(file.length());

        // 文件下载
        try (FileInputStream fileInputStream = new FileInputStream(file);
             BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
             ServletOutputStream outputStream = resp.getOutputStream()
        ){
            StreamUtils.copy(bufferedInputStream, outputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}
